<?php
/**
 * Created by Administrator
 * User: longli
 * VX: isa1589518286
 * Date: 2020/08/17
 * Time: 21:03
 * @link http://www.lmterp.cn
 */

namespace app\common\service\orders;

use app\common\library\OrderHelp;
use app\common\library\Tools;
use app\common\model\Account;
use app\common\model\Channel;
use app\common\model\OrdersPick;
use app\common\model\OrdersPickInfo;
use app\common\model\OrdersReturn;
use app\common\model\SysCountries;
use app\common\model\CsBlacklist;
use app\common\model\Orders;
use app\common\model\OrdersDetail;
use app\common\model\ProductStore;
use app\common\service\BaseService;
use app\common\service\product\PlatformService;
use app\common\service\product\ProductService;
use app\common\service\system\SystemService;
use think\Db;
use think\exception\DbException;
use think\facade\Config;
use think\facade\Log;

/**
 * 订单服务类
 * Class OrderService
 * @package app\common\service\orders
 */
class OrderService extends BaseService
{
    /**
     * 添加订单
     * @param array $orderData 订单信息
     * @date 2020/08/17
     * @author longli
     * @return Orders|bool
     * @example $orderData = [
     *     "order_no" => "订单号",
     *     "order_detail" => [  // 订单情况
     *          [
     *              "sku" => "sku",
     *              "account_id" => 1,
     *          ]
     *      ]
     * ]
     */
    public function addOrder($orderData = [])
    {
        $data = Orders::getFilterField($orderData, '');
        if(empty($data)) return false;
        $data = Tools::trim($data);
        try
        {
            Db::startTrans();
            $order = null;
            // 验证是否需要更新订单
            if(!empty($data['order_id'])) $order = Orders::get($data['order_id']);
            if(empty($order) && !empty($data['order_sn'])) $order = Orders::get(['order_sn' => $data['order_sn']]);
            if(empty($order))
            {
                // 如果国家没有填入则自动带入国家名称
                if(empty($data['buyer_country']) && !empty($data['buyer_country_code']) && ($county = SysCountries::getByCode($data['buyer_country_code'])))
                    $data['buyer_country'] = $county->name_ch;
                // 如果国家简码没有填则自动带入二给简码
                if(empty($data['buyer_country_code']) && !empty($data['buyer_country']) && ($county = SysCountries::getByName($data['buyer_country'])))
                    $data['buyer_country_code'] = $county->code_two;
                // 如果没有填平台则自动带入
                if(empty($data['platform_name']) && !empty($data['account_id']) && ($account = Account::get($data['account_id'])))
                    $data['platform_name'] = $account->platform->name;
                // 处理内部唯一订单号
                if(!isset($data['order_sn']))
                {
                    $platform = 'AUTO';
                    if(!empty($data['account_id']) && ($account = Account::get($data['account_id'])))
                    {
                        $platform = $account->platform->code;
                    }
                    $data['order_sn'] = OrderHelp::generatorOrderSn($platform);
                }
                $order = Orders::create($data)->refresh();
            }
            else
            {
                $order->save($data);
            }
            if(!empty($orderData['order_detail']))
                $this->addOrderDetail($order, $orderData['order_detail']); // 添加订单详情
            $order->computeOrder(); // 计算订单
            \think\facade\Hook::listen('order', $order); // 处理订单后续流程
            Db::commit();
            return $order;
        }catch (DbException $exception)
        {
            Log::info(sprintf("添加订单有误，错误信息：%s", $exception->getMessage()));
            Db::rollback();
        }
        return false;
    }

    /**
     * 添加订单详情
     * @param Orders $order 订单
     * @param array $details 订单详情
     * @date 2020/08/18
     * @author longli
     * @return OrdersDetail|int|null
     */
    public function addOrderDetail(Orders $order, $details = [])
    {
        if(empty($details)) return null;
        if(!isset($details[0])) $details = [$details];
        $orderDetail = null;
        foreach($details as $detail)
        {
            $data = OrdersDetail::getFilterField($detail, '');
            if(empty($data)) return null;
            $data = Tools::trim($data);
            if(empty($data['sku']))
            {
                // 解析平台 SKU
                $skus = PlatformService::getInstance()->getSkuByPlatformSku($data['platform_sku']);
                if(is_array($skus))
                {
                    $data['is_bundle'] = Orders::IS_YES;
                    $data['bdsku'] = join(',', $skus);
                    // 处理多个SKU
                    foreach($skus as $k => $sku)
                    {
                        if($k > 0) $data['price'] = 0; // 把价格算在第一个 SKU
                        $data = ['sku' => $sku] + $data;
                        $this->addOrderDetail($order, $data);
                    }
                }
                else
                {
                    $data['sku'] = $skus;
                }
            }
            if(empty($data['store_id']) && $productStore = ProductStore::getStoreBySku($data['sku']))
            {
                if(empty($data['store_id'])) $data['store_id'] = $productStore->store_id;
                if(empty($data['name_ch'])) $data['name_ch'] = $productStore->product->name_ch;
                if(empty($data['image_url'])) $data['image_url'] = !empty($productStore->image_url) ? $productStore->image_url : $productStore->product->image_url;
                if(empty($data['declare_en'])) $data['declare_en'] = $productStore->product->declare_en;
                if(empty($data['declare_ch'])) $data['declare_ch'] = $productStore->product->declare_ch;
                if(empty($data['declare_price'])) $data['declare_price'] = $productStore->product->declare_price; // 默认取产品库里的人民币申报价格
                if(empty($data['declare_weight'])) $data['declare_weight'] = $productStore->weight; // 默认取产品库里的重量(g)
            }
            $data['order_id'] = $order->order_id;
            $data['order_no'] = $order->order_no;
            $data['total_price'] = floatval($data['price']) * intval($data['qty']);  // 计算总价
            $cost = isset($data['discount']) ? $data['discount'] : 0;
            $cost += isset($data['platform_cost']) ? $data['platform_cost'] : 0;
            $data['total_price_rmb'] = SystemService::getInstance()->exchangeRate($order->currency, $data['total_price'] - $cost);
            $where = !empty($data['detail_id'])
                ? ['detail_id' => $data['detail_id']]
                : ["order_id" => $order->order_id, "sku" => $data['sku']];
            $orderDetail = OrdersDetail::get($where);
            if(!empty($orderDetail))
            {
                $orderDetail->save($data);
            }
            else
            {
                $orderDetail = OrdersDetail::create($data)->refresh();
            }
        }
        return $orderDetail;
    }

    /**
     * 补发订单
     * @param int $orderId 订单id
     * @param array $detail 补发产品详情
     * @example $detail = [
     *      ['sku' => 'A001', 'qty' => 2]
     * ]
     * @date 2021/08/13
     * @author longli
     */
    public function againOrder($orderId, $detail = [])
    {
        $field = ['order_id', 'order_sn', 'order_no', 'account_id', 'platform_name',
            'weight', 'prime_cost', 'order_platform_status', 'payment_method', 'customs_code',
            'order_source_create_time', 'order_pay_time', 'currency', 'buyer_first_name',
            'buyer_last_name', 'consignee', 'buyer_post_code', 'buyer_phone',
            'buyer_mobile', 'buyer_country', 'buyer_country_code', 'buyer_province', 'buyer_city',
            'buyer_district', 'buyer_address_1', 'buyer_address_2', 'buyer_address_3', 'platform_remark'
        ];
        $detailField = ['order_id',  '0 AS price', 'product_code', 'url', 'item_id', 'sku', 'qty', 'platform_sku',
            'name', 'attr', 'customer_remark',
        ];
        $order = Orders::field($field)->with(['detail' => function($query)use($detailField){$query->field($detailField);}])
            ->where("order_id", $orderId)->find();
        $order = Tools::visibleArray(['order_id'], $order->toArray(), false);
        $order['order_sn'] = OrderHelp::generateNextOrderSn($order['order_sn']);
        $orderDetail = [];
        // 如果未指定 SKU 和数量则全部补发
        if(empty($detail))
        {
            $orderDetail = $order['detail'];
        }
        else
        {
            $skus = array_combine(array_column($detail, 'sku'), array_column($detail, 'qty'));
            foreach($order['detail'] as & $d)
            {
                // 如果指定补发只能是订单里的 SKU
                if(!isset($skus[$d['sku']]) || $skus[$d['sku']] < 1) continue;
                // 补发数量不能大于订单购买数量
                if($skus[$d['sku']] > $d['qty']) return false;
                $d['qty'] = $skus[$d['sku']];
                $orderDetail[] = $d;
            }
        }
        if(empty($orderDetail)) return false;
        $order['order_detail'] = $orderDetail;
        return $this->addOrder($order);
    }

    /**
     * 拆单
     * @param Orders|int 订单模型或者订单id
     * @return bool
     * @date 2020/09/02
     * @author longli
     */
    public function splitOrder($order)
    {
        if(is_numeric($order)) $order = Orders::get($order);
        // @todo 拆单
        Log::info("拆单：订单号【】拆为【】");
    }
    /**
     * 合并订单
     * @param int[] $orderIds 订单ID
     * @return bool
     * @date 2020/09/02
     * @author longli
     */
    public function mergeOrder($orderIds = [])
    {
        // @todo 合并订单
        Log::info("合并订单：订单号【】合为【】");
    }

    /**
     * 通过订单 id 删除订单
     * @param int|int[] $ids 订单ID
     * @return bool
     * @date 2020/09/02
     * @author longli
     */
    public function deleteOrderById($ids = [])
    {
        if(empty($ids)) return false;
        if(is_array($ids)) $ids = join(',', $ids);
        try
        {
            Db::startTrans();
            Orders::destroy($ids);
            OrdersDetail::destroy(function($query)use($ids){$query->where("order_id", "in", $ids);});
            Db::commit();
            return true;
        }catch(DbException $e)
        {
            Log::info(sprintf("订单删除失败, 订单ID【%s】", $ids));
            Db::rollback();
        }
        return false;
    }

    /**
     * 通过 html 生成 PDF 发票模板
     * @param string $html 渲染后的html
     * @param string $filename pdf 文件名，如果为空则自动生成
     * @return string
     * @date 2020/12/12
     * @author longli
     */
    public function generateInvoice($html, $filename = '')
    {
        $invoicePath = Config::get("invoice_path");
        $output = ProductService::getInstance()->HTML2PDF($html, $invoicePath, $filename);
        return ".". self::hiddenRootPath($output);
    }

    /**
     * 添加退货
     * @param Orders $order 订单
     * @param array $data 退货详情
     * @date 2021/03/04
     * @author longli
     */
    public function addReturn(Orders $order, $data)
    {
        $oData = OrdersReturn::getFilterField($data, '');
        if(empty($oData)) return false;
        $oData = Tools::trim($oData);
        $ret = null;
        if(isset($oData['rid'])) $ret = OrdersReturn::get($oData['rid']);
        if(empty($ret)) $ret = OrdersReturn::get(['order_id' => $order->order_id]);
        if(isset($oData['return_info']) && is_array($oData['return_info']))
            $oData['return_info'] = json_encode($oData['return_info']);
        if(empty($oData['out_id'])) $oData['out_id'] = $order->warehouse_id;
        if(empty($oData['in_id'])) $oData['in_id'] = $order->warehouse_id;
        if(empty($oData['send_time'])) $oData['send_time'] = Tools::now();
        if(isset($oData['channel_id']) && ($channel = Channel::get($oData['channel_id'])))
            $oData['channel_name'] = $channel->channel_name;
        $oData['order_id'] = $order->order_id;
        try
        {
            Db::startTrans();
            if(!empty($ret))
            {
                $ret->save($oData);
            }
            else
            {
                $ret = OrdersReturn::create($oData);
            }
            if(!empty($ret->return_info))
            {
                $ret->refresh();
                foreach($order->detail as $detail)
                {
                    foreach($ret->return_info as $r)
                    {
                        if($r->qty < 0 || $r->sku != $detail->sku) continue;
                        $detail->return_qty = $r->qty;
                        $detail->save();
                        break;
                    }
                }
                $order->order_status = $order->isReturnAll()
                    ? Orders::ORDER_RETURN
                    : Orders::ORDER_RETURN_PART;
                $order->send_status = Orders::SEND_RETURN_ING;
                $order->save();
            }
            Db::commit();
            return $ret;
        }catch (DbException $exception)
        {
            Log::info(sprintf("订单添加退货失败，错误信息【%s】", $exception->getMessage()));
            Db::rollback();
            return false;
        }
    }

    /**
     * 添加拣货单
     * @param array $pData 拣货单
     * @param array $iData 拣货详情
     * @return OrdersPick
     * @date 2021/07/17
     * @author longli
     */
    public function addPick($pData = [], $iData = [])
    {
        $insert = OrdersPick::getFilterField($pData, '');
        $insert = Tools::trim($insert);
        $pick = null;
        if(isset($insert['pick_id'])) $pick = OrdersPick::get($insert['pick_id']);
        else if(isset($insert['pick_sn'])) $pick = OrdersPick::get(['pick_sn' => $insert['pick_sn']]);
        if(empty($insert['pick_sn'])) $insert['pick_sn'] = $this->generatePickSn();
        if(!empty($pick))
        {
            $pick->save($insert);
        }
        else
        {
            $pick = OrdersPick::create($insert)->refresh();
        }
        // 添加拣货单详情
        if(!isset($iData[0])) $iData = [$iData];
        foreach($iData as $info) $this->addPickInfo($pick, $info);
        return $pick;
    }

    /**
     * 添加拣货单详情
     * @param OrdersPick $pick 拣货单
     * @param array $data 拣货详情
     * @return OrdersPickInfo|null
     * @date 2021/07/17
     * @author longli
     */
    public function addPickInfo(OrdersPick $pick, $data = [])
    {
        $iData = OrdersPickInfo::getFilterField($data, '');
        $iData = Tools::trim($iData);
        $info = null;
        $iData['pick_id'] = $pick->pick_id;
        if(isset($iData['info_id'])) $info = OrdersPickInfo::get($iData['info_id']);
        else if(isset($iData['pick_id']) && isset($iData['order_id']))
            $info = OrdersPickInfo::get(['pick_id' => $iData['pick_id'], 'order_id' => $iData['order_id']]);
        if(!empty($info))
        {
            $info->save($iData);
        }
        else
        {
            $info = OrdersPickInfo::create($iData)->refresh();
        }
        return $info;
    }

    /**
     * 生成拣货单号
     * @return string
     * @date 2021/07/17
     * @author longli
     */
    public function generatePickSn()
    {
        return self::generateSn('pick');
    }
}